//  OutputLanguageWriterKotlin.m

#import "OutputLanguageWriterKotlin.h"
#import "ClassBaseObject.h"
#import "ClassPropertiesObject.h"

@interface OutputLanguageWriterKotlin ()

- (NSString *)kotlinFileForClassObject:(ClassBaseObject *)classObject;
- (NSString *)kotlinTypeForProperty:(ClassPropertiesObject *)property;

@end

@implementation OutputLanguageWriterKotlin

- (BOOL)writeClassObjects:(NSDictionary *)classObjectsDict toURL:(NSURL *)url options:(NSDictionary *)options generatedError:(BOOL *)generatedErrorFlag {
    BOOL filesHaveHadError = NO;
    BOOL filesHaveBeenWritten = NO;

    NSArray *files = classObjectsDict.allValues;

    for (ClassBaseObject *base in files) {
        NSError *fileError = nil;
        NSString *outputFile = [self kotlinFileForClassObject:base];
        NSString *filename = [NSString stringWithFormat:@"%@.kt", base.className];

        [outputFile writeToURL:[url URLByAppendingPathComponent:filename]
                    atomically:YES
                      encoding:NSUTF8StringEncoding
                         error:&fileError];

        if (fileError) {
            filesHaveHadError = YES;
        } else {
            filesHaveBeenWritten = YES;
        }
    }

    if (generatedErrorFlag) { *generatedErrorFlag = filesHaveHadError; }
    return filesHaveBeenWritten;
}

- (NSDictionary *)getOutputFilesForClassObject:(ClassBaseObject *)classObject {
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    dict[[NSString stringWithFormat:@"%@.kt", classObject.className]] = [self kotlinFileForClassObject:classObject];
    return [NSDictionary dictionaryWithDictionary:dict];
}

- (NSSet *)reservedWords {
    return [NSSet setWithObjects:
            @"as", @"break", @"class", @"continue", @"do", @"else", @"false", @"for",
            @"fun", @"if", @"in", @"interface", @"is", @"null", @"object", @"package",
            @"return", @"super", @"this", @"throw", @"true", @"try", @"typealias", @"val",
            @"var", @"when", @"while", @"by", @"catch", @"constructor", @"delegate",
            @"dynamic", @"field", @"file", @"finally", @"get", @"import", @"init",
            @"param", @"property", @"receiver", @"set", @"setparam", @"where",
            nil];
}

- (NSString *)classNameForObject:(ClassBaseObject *)classObject fromReservedWord:(NSString *)reservedWord {
    NSString *capitalized = [reservedWord capitalizedString];
    return [capitalized stringByAppendingString:@"Model"];
}

- (NSString *)propertyNameForObject:(ClassPropertiesObject *)propertyObject inClass:(ClassBaseObject *)classObject fromReservedWord:(NSString *)reservedWord {
    NSString *first = [[reservedWord substringToIndex:1] lowercaseString];
    NSString *rest = reservedWord.length > 1 ? [reservedWord substringFromIndex:1] : @"";
    return [[first stringByAppendingString:rest] stringByAppendingString:@"Property"];
}

- (NSString *)kotlinFileForClassObject:(ClassBaseObject *)classObject {
    NSMutableString *file = [NSMutableString string];
    [file appendString:@"// Generated by JSONAccelerator\n"]; 
    // Optional: package name can be passed via options in future
    // Properties block
    NSMutableArray *props = [NSMutableArray array];
    for (ClassPropertiesObject *property in (classObject.properties).allValues) {
        NSString *typeString = [self kotlinTypeForProperty:property];
        NSString *line = [NSString stringWithFormat:@"    val %@: %@? = null", property.jsonName, typeString];
        [props addObject:line];
    }

    [file appendFormat:@"data class %@(\n", classObject.className];
    for (NSUInteger i = 0; i < props.count; i++) {
        NSString *line = props[i];
        BOOL isLast = (i == props.count - 1);
        [file appendFormat:@"%@%@\n", line, isLast ? @"" : @","];
    }
    [file appendString:@")\n"]; 
    return file;
}

- (NSString *)kotlinTypeForProperty:(ClassPropertiesObject *)property {
    switch (property.type) {
        case PropertyTypeString:
            return @"String";
        case PropertyTypeArray: {
            switch (property.collectionType) {
                case PropertyTypeString:
                    return @"List<String>";
                case PropertyTypeInt:
                    return @"List<Int>";
                case PropertyTypeDouble:
                    return @"List<Double>";
                case PropertyTypeBool:
                    return @"List<Boolean>";
                case PropertyTypeClass:
                    return [NSString stringWithFormat:@"List<%@>", property.referenceClass.className];
                default:
                    return @"List<Any>";
            }
        }
        case PropertyTypeDictionary:
            return @"Map<String, Any>";
        case PropertyTypeInt:
            return @"Int";
        case PropertyTypeBool:
            return @"Boolean";
        case PropertyTypeDouble:
            return @"Double";
        case PropertyTypeClass:
            return property.referenceClass.className ?: @"Any";
        case PropertyTypeOther:
        default:
            return @"Any";
    }
}

@end


